package com.project.frame.common.aop;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath;
import com.project.frame.common.model.BaseResp;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * desc
 *
 * @author cjq
 * @date 2022/4/5
 */
@Aspect
@Component
@Slf4j
public class LogAspect {

    @Pointcut("( @annotation(org.springframework.web.bind.annotation.GetMapping)" +
            "||@annotation(org.springframework.web.bind.annotation.PostMapping)" +
            "||@annotation(org.springframework.web.bind.annotation.PatchMapping)" +
            "||@annotation(org.springframework.web.bind.annotation.DeleteMapping)" +
            "||@annotation(org.springframework.web.bind.annotation.RequestMapping) ) " +
            "&& !@annotation(com.project.frame.common.annotation.LogIgnore) ")
    public void LogAspect() {
    }

    @Around("LogAspect()")
    public Object controllerLog(ProceedingJoinPoint pdj) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

        String url = request.getRequestURL().toString();
        String requestMethod = request.getMethod();

        String function = pdj.getSignature().getDeclaringTypeName() + "." + pdj.getSignature().getName();
        String params = getArgs(pdj);
        String ip = getRemoteIP(request);

        MethodSignature sign = (MethodSignature) pdj.getSignature();
        Method method = sign.getMethod();
        Class declaringType = sign.getDeclaringType();

        Api api = (Api) declaringType.getAnnotation(Api.class);
        ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);

        String module = "";
        String operate = "";
        if (api != null) {
            module = api.value().replaceAll("控制器", "").replaceAll("controller", "");
        }
        if (apiOperation != null) {
            operate = apiOperation.value();
        }


        // 执行原方法并获取返回结果
        Object[] args = pdj.getArgs();
        Object result = pdj.proceed(args);


        int state = 0;
        String response;

        try{
            response = JSON.toJSONString(result);
            try {
                state = Integer.valueOf(String.valueOf(JSONPath.read(response, "$.code")));
                if (BaseResp.RC_OK != state) {
                    state = 1;
                }
            } catch (NumberFormatException e) {
                state = 1;
            }
        }catch(Exception e){
            e.printStackTrace();
        }
        log.info("ip={}",ip);
        log.info("module={}",module);
        log.info("function={}",function);
        log.info("operate={}",operate);
        log.info("state={}",state);
        log.info("requestMethod={}",requestMethod);
        log.info("params={}",params);
        log.info("url={}",url);
        log.info("result={}",result);
        return result;
    }


    public String getRemoteIP(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;

    }
    private static String getArgs(ProceedingJoinPoint joinPoint) {
        // 参数名数组
        Signature signature = joinPoint.getSignature();
        // 参数值
        Object[] args = joinPoint.getArgs();
        String[] parameterNames = ((MethodSignature) signature).getParameterNames();
        JSONObject paramMap = new JSONObject();
        for (int index = 0; index < args.length; index++) {
            Object arg = args[index];
            // 当入参为文件流，只存放一些基本信息
            if (args[index] instanceof MultipartFile) {
                Map<String, Object> fileInfo = new HashMap<>();
                MultipartFile file = (MultipartFile) args[index];
                fileInfo.put("name", file.getOriginalFilename());
                fileInfo.put("size", file.getSize());
                fileInfo.put("contentType", file.getContentType());
                arg = fileInfo;
            } else if (args[index] instanceof ServletRequest) { // 如果拦截器类型忽略
                continue;
            }

            paramMap.put(parameterNames[index], arg);

        }
        return JSON.toJSONString(paramMap);
    }

}
